package com.watson.todolist.testing;

import java.security.GeneralSecurityException;
import java.util.List;

import junit.framework.Assert;

import com.watson.todolist.EditTodoItemActivity;
import com.watson.todolist.R;
import com.watson.todolist.ViewTodoItemActivity;
import com.watson.todolist.database.AccountManager;
import com.watson.todolist.database.DatabaseManager;
import com.watson.todolist.database.ToDoListManager;
import com.watson.todolist.to.TodoItem;

import android.app.Instrumentation;
import android.database.sqlite.SQLiteDatabase;
import android.location.Address;
import android.location.Geocoder;
import android.test.ActivityInstrumentationTestCase2;
import android.test.AndroidTestCase;
import android.widget.EditText;
import android.widget.TextView;

/**
 * This is for M9 Junit testing. This tests the retrieval of to do items from
 * the database after being created and makes sure it stored the correct
 * information that the user inputed. It also tests the accuracy and possible
 * errors that could occur with our location management system in order to plan
 * out appropriate counter measures to things such as slightly incorrect
 * addresses retrieved from hardcodded long/lat coordinates.
 * 
 * @author Jasko Muminhodzic
 * @version 1.0
 * 
 */
public class JaskoTest1 extends AndroidTestCase {

	/**
	 * This method tests the getToDoListItemByTodoId() method. It ensures that
	 * the valid data inputed by the user is correctly stored and passed on to
	 * the database for storage. White box testing is implemented by testing
	 * every line of code is called in the said method. Black box testing is
	 * implemented by testing with a wide range of possible input data and by
	 * different user accounts.
	 * 
	 * @throws Throwable
	 */
	public void testCorrectToDoItemRetrieved() throws Throwable {
		// open and setup db
		DatabaseManager dbManager = new DatabaseManager();
		SQLiteDatabase db = dbManager.open(getContext());
		ToDoListManager todoListManager = new ToDoListManager(db);
		AccountManager accountManager = new AccountManager(db);

		// data for item 1
		String name1 = "1a";
		String desc1 = "";
		int category1 = 0;
		int recurrence1 = 0;
		int complete1 = 0;
		long time1 = 0;
		long lat1 = 0;
		long lon1 = 0;
		long prior1 = 0;

		// data for item 2
		String name2 = "2a";
		String desc2 = "hey";
		int category2 = 1;
		int recurrence2 = 0;
		int complete2 = 0;
		long time2 = 0;
		long lat2 = -1;
		long lon2 = -1;
		long prior2 = 0;

		// data for item 2
		String name3 = "3a";
		String desc3 = "belafakd";
		int category3 = 2;
		int recurrence3 = 0;
		int complete3 = 0;
		long time3 = 0;
		long lat3 = -50;
		long lon3 = 40;
		long prior3 = 0;

		// Create 3 different Accounts for testing purposes
		long userId1 = accountManager.createUserAccount("TestAccount1",
				"testaccount1@email.com", "testaccount1");
		long userId2 = accountManager.createUserAccount("TestAccount2",
				"testaccount2@email.com", "testaccount2");
		long userId3 = accountManager.createUserAccount("TestAccount3",
				"testaccount3@email.com", "testaccount3");

		// Create todo items for Test Accounts
		long todoid = todoListManager.createTodoListItem(userId1, name1,
				category1, time1, lat1, lon1, desc1, recurrence1, prior1,
				complete1);
		long todoid2 = todoListManager.createTodoListItem(userId2, name2,
				category2, time2, lat2, lon2, desc2, recurrence2, prior2,
				complete2);
		long todoid3 = todoListManager.createTodoListItem(userId3, name3,
				category3, time3, lat3, lon3, desc3, recurrence3, prior3,
				complete3);

		// retrieve todo items
		TodoItem todoItem1 = todoListManager.getTodoListItemByTodoId(todoid);
		TodoItem todoItem2 = todoListManager.getTodoListItemByTodoId(todoid2);
		TodoItem todoItem3 = todoListManager.getTodoListItemByTodoId(todoid3);

		// Tests that the item was created and is not null
		Assert.assertTrue(todoItem1 != null);
		Assert.assertTrue(todoItem2 != null);
		Assert.assertTrue(todoItem3 != null);

		// This tests that the retrieved item is exactly as it was created.
		for (int i = 0; i < 3; i++) {
			if (i == 0) {
				toDoItemCheck(todoItem1, name1, desc1, category1, recurrence1,
						complete1, time1, lat1, lon1, prior1);
			} else if (i == 1) {
				toDoItemCheck(todoItem2, name2, desc2, category2, recurrence2,
						complete2, time2, lat2, lon2, prior2);
			} else if (i == 2) {
				toDoItemCheck(todoItem3, name3, desc3, category3, recurrence3,
						complete3, time3, lat3, lon3, prior3);
			}
		}

		// close db
		dbManager.close();

	}

	/**
	 * This is a helper method to help the test create and retrieve item method.
	 * It checks/tests if the users information is what was passed in through
	 * the parameters.
	 * 
	 * @param item
	 * @param name
	 * @param desc
	 * @param category
	 * @param recurrence
	 * @param complete
	 * @param time
	 * @param lat
	 * @param lon
	 * @param prior
	 */
	private void toDoItemCheck(TodoItem item, String name, String desc,
			int category, int recurrence, int complete, long time, long lat,
			long lon, long prior) {
		// This tests that the retrieved item is exactly as it was created.
		for (int i = 0; i < 9; i++) {
			switch (i) {
			case 0:
				assertEquals(name, item.getTodoItemName());
				break;
			case 1:
				assertTrue(category == item.getTodoItemCategoryCode());
				break;
			case 2:
				assertTrue((time == item.getTodoTime()));
				break;
			case 3:
				assertTrue((lat == item.getLatitude()));
				break;
			case 4:
				assertTrue((lon == item.getLongitude()));
				break;
			case 5:
				assertEquals(desc, item.getDescription());
				break;
			case 6:
				assertTrue(recurrence == item.getAlarmRecurrenceType());
				break;
			case 7:
				assertTrue((prior == item.getPriorAlarmReminderTime()));
				break;
			case 8:
				assertTrue(complete == item.getTodoCompleted());
				break;
			}
		}
	}

	/**
	 * This method tests the accuracy and possible bugs that could arise from
	 * mismanagement of latitude and longitude coordinates that are stored in
	 * each todoitem. The conversion from a named address or other longitude and
	 * latitude could cause the wrong location to be displayed from what the
	 * original user input was. Therefore, I wanted to test all possible errors
	 * that could arise and devise a way to reduce this error from occurring in
	 * our application from the data of this test method. White box testing is
	 * implemented by testing that every line of code from the user item
	 * creation, and username is completed and retrieved optimally. Black Box
	 * testing is done by testing different types of locations and from
	 * different users.
	 * 
	 * @throws Throwable
	 */
	public void testLocationAccurracy() throws Throwable {

		// setup/open db
		DatabaseManager dbManager = new DatabaseManager();
		SQLiteDatabase db = dbManager.open(getContext());
		ToDoListManager todoListManager = new ToDoListManager(db);
		AccountManager accountManager = new AccountManager(db);

		// Create 3 different Accounts for testing purposes
		long userId1 = accountManager.createUserAccount("TestAccount1",
				"testaccount1@email.com", "testaccount1");
		long userId2 = accountManager.createUserAccount("TestAccount2",
				"testaccount2@email.com", "testaccount2");
		long userId3 = accountManager.createUserAccount("TestAccount3",
				"testaccount3@email.com", "testaccount3");

		// geocoder setup
		Geocoder gc = new Geocoder(getContext());

		// setup locations
		// 225 North Avenue Atlanta, GA 30332 aka 33.772423,-84.395052
		// 1070 Omaha Drive, Norcross, GA 30093 aka 33.887486,-84.192794
		// 38-62 Hillman St, Springfield, MA 01103 aka 42.104441,-72.589506
		List<Address> list1 = gc.getFromLocationName(
				"225 North Avenue  Atlanta, GA 30332", 1);
		List<Address> list2 = gc.getFromLocationName(
				"1070 Omaha Drive, Norcross, GA 30093", 1);
		List<Address> list3 = gc.getFromLocationName(
				"38-62 Hillman St, Springfield, MA 01103", 1);

		// given the scope of the accuracy of geocoder converting, it is
		// advisable to only check for the street addresses, unless checking for
		// multiple
		// possibilities from the address lists, in which case, a correct
		// address could be found.
		String address1 = "North Avenue";
		String address2 = "Omaha Dr";
		String address3 = "Dwight St";

		// retrieving the long and lat coordinates of the locations
		float locationOneLat = (float) list1.get(0).getLatitude();
		float locationOneLong = (float) list1.get(0).getLongitude();

		float locationTwoLat = (float) list2.get(0).getLatitude();
		float locationTwoLong = (float) list2.get(0).getLongitude();

		float locationThreeLat = (float) list3.get(0).getLatitude();
		float locationThreeLong = (float) list3.get(0).getLongitude();

		// Create todo items for different accounts
		long todoid = todoListManager.createTodoListItem(userId1, "1a", 0, 0,
				locationOneLat, locationOneLong, "", 0, 0, 0);
		long todoid2 = todoListManager.createTodoListItem(userId2, "2a", 0, 0,
				locationTwoLat, locationTwoLong, "", 0, 0, 0);
		long todoid3 = todoListManager.createTodoListItem(userId3, "3a", 0, 0,
				locationThreeLat, locationThreeLong, "", 0, 0, 0);

		// collect the todo items for retrieval of stored coordinates
		TodoItem todoItem1 = todoListManager.getTodoListItemByTodoId(todoid);
		TodoItem todoItem2 = todoListManager.getTodoListItemByTodoId(todoid2);
		TodoItem todoItem3 = todoListManager.getTodoListItemByTodoId(todoid3);

		// re-populate list with address
		list1 = gc.getFromLocation(todoItem1.getLatitude(),
				todoItem1.getLongitude(), 1);
		list2 = gc.getFromLocation(todoItem2.getLatitude(),
				todoItem2.getLongitude(), 1);
		list3 = gc.getFromLocation(todoItem3.getLatitude(),
				todoItem3.getLongitude(), 1);

		// check to see if the addresses found are within range of what the user
		// inputed
		Assert.assertTrue(list1.get(0).getAddressLine(0).contains(address1));
		Assert.assertTrue(list2.get(0).getAddressLine(0).contains(address2));
		Assert.assertTrue(list3.get(0).getAddressLine(0).contains(address3));

		// close db
		dbManager.close();
	}
}
